<template>
    <el-form :id="id" :label-position="vertical ? 'top' : 'right'" :label-width="labelWidth || 'auto'" ref="form"
        :model="model" :rules="validationRules" :validate-on-rule-change="false" :inline-message="!vertical"
        :disabled="disabled" :class="theme ? ('theme-' + theme) : null" :size="size" :status-icon="statusIcon">
        <slot></slot>
        <el-form-item class="w-100" :label-width="labelWidth" v-if="submit !== undefined && submit !== null">
            <el-button :type="theme || 'primary'" @click="toSubmit" v-if="submit !== false">
                {{ _submitText }}
            </el-button>
            <el-button type="default" @click="toCancel" v-if="cancel !== false">{{ cancelText }}</el-button>
        </el-form-item>
    </el-form>
</template>

<script>
import $ from 'jquery';

export default {
    name: 'TnxelSubmitForm',
    props: {
        /**
         * 所属滚动容器的选择器
         */
        container: {
            type: String,
            default: 'main',
        },
        model: {
            type: Object,
            required: true,
        },
        rules: [String, Object], // 加载字段校验规则的URL地址，或规则集对象
        rulesApp: { // 加载字段校验规则的应用名称
            type: String,
            default: () => window.tnx.componentDefaultApp, // 设置为方法以延时加载，确保更改的值生效
        },
        rulesLoaded: Function, // 规则集加载后的附加处理函数，仅在rule为字符串类型的URL地址时有效
        submit: {
            type: [Function, Boolean],
            default: null,
        },
        submitText: String,
        theme: String,
        size: String,
        statusIcon: {
            type: Boolean,
            default: false,
        },
        cancel: {
            type: [String, Function, Boolean],
            default: true
        },
        cancelText: {
            type: String,
            default: '取消'
        },
        vertical: {
            type: Boolean,
            default: false
        },
        errorFocus: {
            type: Boolean,
            default: false,
        },
        labelWidth: [String, Number],
    },
    data() {
        return {
            id: window.tnx.util.string.random(32),
            validationRules: {},
            disabled: false,
            topOffset: 0,
            fieldNames: [],
        };
    },
    computed: {
        _submitText() {
            if (this.submitText) {
                return this.submitText;
            }
            return this.cancel === false ? '保存' : '提交';
        }
    },
    watch: {
        rules() {
            this.initRules();
        },
    },
    mounted() {
        this.initRules();

        this.$nextTick(() => {
            let container = $(this.container);
            if (container.length) {
                this.topOffset = $('#' + this.id).offset().top - container.offset().top - 16;
            }
        });
    },
    methods: {
        initRules() {
            if (this.rules) {
                if (typeof this.rules === 'string') {
                    const vm = this;
                    window.tnx.app.rpc.getMeta(this.rules, meta => {
                        if (vm.rulesLoaded) {
                            vm.rulesLoaded(meta.$rules);
                        } else {
                            vm.$emit('rules-loaded', meta.$rules);
                        }
                        vm.validationRules = meta.$rules;
                        delete meta.$rules;
                        this.$emit('meta', meta);
                        vm.fieldNames = Object.keys(meta);
                    }, this.rulesApp);
                } else {
                    this.validationRules = this.rules;
                }
            } else {
                this.validationRules = {};
            }
        },
        disable(disabled) {
            this.disabled = disabled !== false;
        },
        focusError() {
            let $form = $('#' + this.id);
            let $item = $('.el-form-item.is-error:first', $form);
            if ($item.length) {
                let top = $item.offset().top - $form.offset().top + this.topOffset;
                $(this.container).scrollTop(top);
            }
        },
        validate(errorFocus) {
            let _this = this;
            return new Promise((resolve) => {
                this.$refs.form.validate().then(valid => {
                    if (!valid && _this.errorFocus && errorFocus !== false) {
                        _this.$nextTick(() => {
                            _this.focusError.call(_this);
                        });
                    }
                    resolve(valid);
                }).catch(invalidFields => {
                    if (_this.errorFocus && errorFocus !== false) {
                        _this.$nextTick(() => {
                            _this.focusError.call(_this);
                        });
                    }
                    resolve(false);
                });
            });
        },
        validateField(props, errorFocus) {
            let _this = this;
            return new Promise((resolve) => {
                this.$refs.form.validateField(props, (errorMessage) => {
                    if (errorMessage && _this.errorFocus && errorFocus !== false) {
                        _this.$nextTick(() => {
                            _this.focusError.call(_this);
                        });
                    }
                    resolve(errorMessage);
                });
            });
        },
        clearValidate(props) {
            this.$refs.form.clearValidate(props);
        },
        async toSubmit(callback, disabled) {
            let success = await this.validate();
            if (success) {
                if (typeof callback !== 'function') {
                    callback = this.submit;
                }
                if (typeof callback === 'function') {
                    if (disabled !== false) {
                        this.disable();
                    }
                    return callback(this);
                }
            }
            return success;
        },
        toCancel() {
            if (typeof this.cancel === 'function') {
                this.cancel();
            } else if (typeof this.cancel === 'string') {
                this.$router.back(this.cancel);
            } else if (this.cancel !== false) {
                this.$router.back();
            }
        },
        getFieldNames() {
            return this.fieldNames;
        }
    }
}
</script>
